//
//  MPBTools+EncryptDecrypt.m
//  MiaoPai
//
//  Created by jiaxuzhou on 2017/6/10.
//  Copyright © 2017年 Jeakin. All rights reserved.
//
//


#import "MPBTools+EncryptDecrypt.h"
#import "GTMBase64.h"
/// 使用CC_MD5
#import <CommonCrypto/CommonDigest.h>
#import <CommonCrypto/CommonCryptor.h>


@implementation MPBTools (EncryptDecrypt)


#pragma mark - *********************************** MD5 加密，不可逆 **********************************

/// 16位MD5加密，给指定字符串，返回全是大写字母
+ (NSString *)mp_EncryptByMD5Upper16WithStr:(NSString *)stringSource
{
    CC_MD5_CTX md5;
    CC_MD5_Init (&md5);
    CC_MD5_Update (&md5,([stringSource UTF8String]), (CC_LONG)[stringSource length]);
    
    unsigned char digest[CC_MD5_DIGEST_LENGTH];
    CC_MD5_Final (digest, &md5);
    
    NSString *stringResault = [NSString stringWithFormat:
            @"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
            digest[0], digest[1], digest[2], digest[3],
            digest[4], digest[5], digest[6], digest[7],
            digest[8], digest[9], digest[10], digest[11],
            digest[12], digest[13], digest[14], digest[15]
            ];
    
    return stringResault;
}

+ (NSString *)mp_EncryptByMD5Upper16WithData:(NSData *)dataSource
{
    const char *cStr = (const char *)[dataSource bytes];
    unsigned char result[CC_MD5_DIGEST_LENGTH];
    CC_MD5(cStr, (CC_LONG)[dataSource length], result);
    
    CC_MD5_CTX md5;
    CC_MD5_Init (&md5);
    CC_MD5_Update (&md5,cStr, (CC_LONG)[dataSource length]);
    
    unsigned char digest[CC_MD5_DIGEST_LENGTH];
    CC_MD5_Final (digest, &md5);
    
    NSString *stringResault = [NSString stringWithFormat:
                               @"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
                               digest[0], digest[1], digest[2], digest[3],
                               digest[4], digest[5], digest[6], digest[7],
                               digest[8], digest[9], digest[10], digest[11],
                               digest[12], digest[13], digest[14], digest[15]
                               ];
    
    return stringResault;
}

/// 16位MD5加密，给指定字符串，返回全是小写字母
+ (NSString *)mp_EncryptByMD5Lower16Str:(NSString *)stringSource
{
    CC_MD5_CTX md5;
    CC_MD5_Init (&md5);
    CC_MD5_Update (&md5,([stringSource UTF8String]), (CC_LONG)[stringSource length]);
    
    unsigned char digest[CC_MD5_DIGEST_LENGTH];
    CC_MD5_Final (digest, &md5);
    NSString *stringResault = [NSString stringWithFormat: @"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
                   digest[0],  digest[1],
                   digest[2],  digest[3],
                   digest[4],  digest[5],
                   digest[6],  digest[7],
                   digest[8],  digest[9],
                   digest[10], digest[11],
                   digest[12], digest[13],
                   digest[14], digest[15]];
    
    return stringResault;
}

+ (NSString *)mp_EncryptByMD5Lower16Data:(NSData *)dataSource
{
    const char *cStr = (const char *)[dataSource bytes];
    CC_MD5_CTX md5;
    CC_MD5_Init (&md5);
    CC_MD5_Update (&md5,cStr, (CC_LONG)[dataSource length]);
    
    unsigned char digest[CC_MD5_DIGEST_LENGTH];
    CC_MD5_Final (digest, &md5);
    NSString *stringResault = [NSString stringWithFormat: @"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
                               digest[0],  digest[1],
                               digest[2],  digest[3],
                               digest[4],  digest[5],
                               digest[6],  digest[7],
                               digest[8],  digest[9],
                               digest[10], digest[11],
                               digest[12], digest[13],
                               digest[14], digest[15]];
    
    return stringResault;
}


#pragma mark - ******************************* AES128位Hex 加解密 ***********************************

/**
 AES128位Hex方式加密函数
 
 @param aStr 要加密的字符串
 @param aKey AES的加密key
 @return 返回加密之后的字符串 该字符串先走AES然后走Hex
 */
+ (NSString *)mp_AES128HexEncryptStr:(NSString *)aStr password:(NSString *)aKey
{
    NSData* data = [aStr dataUsingEncoding:NSUTF8StringEncoding];

    return [self mp_AES128HexEncryptData:data password:aKey];
}

+ (NSString *)mp_AES128HexEncryptData:(NSData *)aData password:(NSString *)aKey
{
    if (aKey == nil || (aKey.length != 16 && aKey.length != 32))
    {
        return nil;
    }
    
    NSData* data = aData;

    char keyPtr[kCCKeySizeAES128+1];
    memset(keyPtr, 0, sizeof(keyPtr));
    [aKey getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
    
    
    char ivPtr[kCCBlockSizeAES128+1];
    memset(ivPtr, 0, sizeof(ivPtr));
    [aKey getCString:ivPtr maxLength:sizeof(ivPtr) encoding:NSUTF8StringEncoding];
    
    NSUInteger dataLength = [data length];
    
    int diff = kCCKeySizeAES128 - (dataLength % kCCKeySizeAES128);
    unsigned long newSize = 0;
    
    if(diff > 0)
    {
        newSize = dataLength + diff;
    }
    
    char dataPtr[newSize];
    memcpy(dataPtr, [data bytes], [data length]);
    for(int i = 0; i < diff; i++)
    {
        // 这里是关键，这里是使用NoPadding的
        dataPtr[i + dataLength] = 0x0000;
    }
    
    size_t bufferSize = newSize + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);
    memset(buffer, 0, bufferSize);
    
    size_t numBytesCrypted = 0;
    
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
                                          kCCAlgorithmAES128,
                                          kCCOptionECBMode,
                                          [aKey UTF8String],
                                          kCCKeySizeAES128,
                                          ivPtr,
                                          dataPtr,
                                          sizeof(dataPtr),
                                          buffer,
                                          bufferSize,
                                          &numBytesCrypted);
    
    if (cryptStatus == kCCSuccess)
    {
        NSData *resultData = [NSData dataWithBytesNoCopy:buffer length:numBytesCrypted];
        
        return [self mp_EncryptByHEXData:resultData];
    }
    
    free(buffer);
    
    return nil;
}

+ (NSString *)mp_AES128HexDecryptData:(NSData *)aData password:(NSString *)aKey
{
    NSString *strEdc = [[NSString alloc] initWithData:aData encoding:NSUTF8StringEncoding];
    return [self mp_AES128HexDecryptStr:strEdc password:aKey];
}

/**
 AES128位Hex方式解密函数
 
 @param aStr 要解密的字符串
 @param aKey AES的加密key
 @return 返回解密之后的字符串 先进行Hex之后再进行AES解密
 */
+ (NSString *)mp_AES128HexDecryptStr:(NSString *)aStr password:(NSString *)aKey
{
    if (aKey == nil || (aKey.length != 16 && aKey.length != 32))
    {
        return nil;
    }
    
    char keyPtr[kCCKeySizeAES128 + 1];
    memset(keyPtr, 0, sizeof(keyPtr));
    [aKey getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
    
    char ivPtr[kCCBlockSizeAES128 + 1];
    memset(ivPtr, 0, sizeof(ivPtr));
    [aKey getCString:ivPtr maxLength:sizeof(ivPtr) encoding:NSUTF8StringEncoding];
    
    NSData *data = [self mp_DecryptByHEXStr:aStr];
    NSUInteger dataLength = [data length];
    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);
    
    size_t numBytesCrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
                                          kCCAlgorithmAES128,
                                          kCCOptionECBMode,
                                          [aKey UTF8String],
                                          kCCBlockSizeAES128,
                                          ivPtr,
                                          [data bytes],
                                          dataLength,
                                          buffer,
                                          bufferSize,
                                          &numBytesCrypted);
    if (cryptStatus == kCCSuccess)
    {
        NSData *resultData = [NSData dataWithBytesNoCopy:buffer length:numBytesCrypted];
        NSString *decoded=[[NSString alloc] initWithData:resultData encoding:NSUTF8StringEncoding];
        
        return decoded;
    }
    
    free(buffer);
    
    return nil;
}


#pragma mark - *********************************** HEX 加解密 ***************************************

+ (NSString *)mp_EncryptByHEXStr:(NSString *)aStr
{
    NSData *data = [aStr dataUsingEncoding:NSASCIIStringEncoding];
   return [MPBTools mp_EncryptByHEXData:data];
}

/// HEX加密
+ (NSString *)mp_EncryptByHEXData:(NSData *)strData;
{
    NSString *str = @"0123456789ABCDEF";
    
    NSMutableString *retStr = [NSMutableString string];
    const Byte *bs = [strData bytes];
    int bit;
    for (int i = 0; i < strData.length; i++)
    {
        bit = (bs[i] & 0x0f0) >> 4;
        [retStr appendString:[str substringWithRange:NSMakeRange(bit, 1)]];
        bit = bs[i] & 0x0f;
        [retStr appendString:[str substringWithRange:NSMakeRange(bit, 1)]];
    }
    return retStr;
}

/// HEX解密
+ (NSData *)mp_DecryptByHEXStr:(NSString *)aStr
{
    NSString *str = @"0123456789ABCDEF";
    
    aStr = [aStr uppercaseString];
    Byte *bytes = (Byte *)[[NSMutableData dataWithCapacity:aStr.length/2]bytes];
    NSUInteger n;
    for (int i = 0; i < aStr.length/2; i++)
    {
        n = [str rangeOfString:[aStr substringWithRange:NSMakeRange(2*i, 1)]].location << 4;
        n += [str rangeOfString:[aStr substringWithRange:NSMakeRange(2*i+1, 1)]].location;
        bytes[i] = (Byte) (n & 0xff);
    }
    return [NSData dataWithBytes:bytes length:aStr.length/2];
}

+ (NSData *)mp_DecryptByHEXData:(NSData *)aData
{
    NSString *strEdc = [[NSString alloc] initWithData:aData encoding:NSUTF8StringEncoding];
    
    return [self mp_DecryptByHEXStr:strEdc];
}


#pragma mark - ********************************* Base64 加解密 **************************************

/// Base64加密
+ (NSString *)mp_EncryptByBase64Str:(NSString *)aStr
{
    NSData *data = [aStr dataUsingEncoding:NSASCIIStringEncoding];
    NSData *dataEnc = [GTMBase64 encodeData:data];
    return [[NSString alloc] initWithData:dataEnc
                                 encoding:NSUTF8StringEncoding];
}

+ (NSString *)mp_EncryptByBase64Data:(NSData *)strData
{
    NSData *dataEnc = [GTMBase64 encodeData:strData];
    return [[NSString alloc] initWithData:dataEnc
                                 encoding:NSUTF8StringEncoding];
}

/// Base64解密
+ (NSData *)mp_DecryptByBase64Str:(NSString *)aStr
{
    return [GTMBase64 decodeString:aStr];
}

+ (NSData *)mp_DecryptByBase64Data:(NSData *)aData
{
    return [GTMBase64 decodeData:aData];
}


@end
